/**
 * Keybind 在记录每个键盘按键的时候是正交的，也就是说可以同时响应多个按键并触发不同的事件
 * ! 不能将键合成为字符串进行判断，这样会不能正交
 */
type Callback = (e: Laya.LayaEventData<KeyboardEvent>) => void;
export default class Keybind {
    constructor() {}
    init() {
        Laya.stage.on<KeyboardEvent>(
            Laya.Event.KEY_UP,
            this,
            this.onKeyUp as any
        );
        Laya.stage.on<KeyboardEvent>(
            Laya.Event.KEY_DOWN,
            this,
            this.onKeyDown as any
        );
    }
    // 以键的同时成立为条件，指向第二个参数函数
    keyDown: [number[], Callback][] = [];

    // 存储同时按下的键位
    keyList: Set<number> = new Set();

    /** 提供给laya 的绑定函数 */
    onKeyUp(e: Laya.LayaEventData<KeyboardEvent>) {
        e.nativeEvent.preventDefault();
        this.keyList.delete(e.keyCode!);
        this.checkEvent(e);
    }
    /** 提供给laya 的绑定函数 */
    onKeyDown(e: Laya.LayaEventData<KeyboardEvent>) {
        e.nativeEvent.preventDefault();
        this.keyList.add(e.keyCode!);
        this.checkEvent(e);
    }

    checkEvent(e: Laya.LayaEventData<KeyboardEvent>) {
        this.keyDown.forEach(([keyCodes, event]) => {
            const check = keyCodes.every((code) => this.keyList.has(code));
            if (check) event.call(null, e);
        });
    }
    /** 批量设置事件 */
    setEvents(template: [number[], Callback][]) {
        template.forEach(([keyCodes, event]) => {
            this.on(keyCodes, event);
        });
    }
    on(keyCodes: number[], callback: Callback): void {
        keyCodes.sort((a, b) => a - b);
        this.keyDown.push([keyCodes, callback]);
    }
    once(keyCodes: number[], callback: Callback) {
        keyCodes.sort((a, b) => a - b);
        const event = (e: Laya.LayaEventData<KeyboardEvent>) => {
            callback(e);
            this.off(keyCodes, event);
        };
        this.keyDown.push([keyCodes, event]);
    }
    off(keyCodes: number[], callback: Callback) {
        const target = this.keyDown;
        keyCodes.sort((a, b) => a - b);
        for (let index = 0; index < target.length; index++) {
            const [KeyCodes, Callback] = target[index];
            if (
                JSON.stringify(keyCodes) === JSON.stringify(KeyCodes) &&
                callback === Callback
            ) {
                target.splice(index, 1);
            }
            break;
        }
    }
}
